<?php
abstract class NoBusinessBase_Model_Base //implements JsonSerializable
{

/************************************************************************/
/* Member Variables                                                     */
/************************************************************************/

   private $mNotifiers = array();
   private $mExtraFields = array();
   
/************************************************************************/
/* Constructor                                                          */
/************************************************************************/

   public function __construct(array $options = null)
   {
      if (is_array($options))
         $this->setOptions($options);
   }

/************************************************************************/
/* Magic Functions                                                      */
/************************************************************************/

   public function __set($name, $value)
   {
      $method = 'set' . $name;
      if (('mapper' == $name) || !method_exists($this, $method))
         throw new Exception('Invalid Model property');

      $this->$method($value);
   }

   public function __get($name)
   {
      $method = 'get' . $name;
      if (('mapper' == $name) || !method_exists($this, $method))
      {
         throw new Exception("Invalid Model property: \"$method\"");
      }

      return $this->$method();
   }

   public static function modelProps()
   {
      return array();
   }
   
   public function toJson()
   {
      return Zend_Json::encode($this->toArray());
   }
   
   public function jsonSerialize()
   {
      return $this->toArray();
   }

/************************************************************************/
/* Notifiers                                                            */
/************************************************************************/

   public function addNotifier(NoBusinessBase_Model_NotifierBase $pNotifier, $addToFront = false)
   {
      if($addToFront)
      {
         array_unshift($this->mNotifiers, $pNotifier);
      }
      else
      {
         $this->mNotifiers[] = $pNotifier;
      }
   }

   public function getNotifier(NoBusinessBase_Model_NotifierBase $pNotifierToFind)
   {
      $findClassName = get_class($pNotifierToFind);
      foreach($this->mNotifiers as $key => $pNotifier)
      {
         if(get_class($pNotifier) != $findClassName)
            continue;

         return $pNotifier;
      }
      return null;
   }
   
   public function removeNotifier(NoBusinessBase_Model_NotifierBase $pNotifierToRemove)
   {
      $removeClassName = get_class($pNotifierToRemove);
      foreach($this->mNotifiers as $key => $pNotifier)
      {
         if(get_class($pNotifier) != $removeClassName)
            continue;
         
         // Remove class
         unset($this->mNotifiers[$key]);
         
         return $pNotifier;
      }
      return null;
   }

   public function clearNotifiers()
   {
      $this->mNotifiers = array();
   }
   
   public function notifiers()
   {
      if(!NoBusinessBase_Model_NotifierBase::isEnabled())
         return array();
      
      return $this->mNotifiers;
   }

/************************************************************************/
/* Public Interface                                                     */
/************************************************************************/

   public function addExtraField($key, $value)
   {
      $this->mExtraFields[$key] = $value;
   }

   public function getExtraField($key)
   {
      return isset($this->mExtraFields[$key]) ? $this->mExtraFields[$key] : null;
   }

   public function getExtraFields()
   {
      return $this->mExtraFields;
   }
   
   public function setOptions(array $options)
   {
      $optionsSet = array();
      $methods = get_class_methods($this);
      foreach ($options as $key => $value)
      {
         $method = 'set' . ucfirst($key);
         if (in_array($method, $methods) && !in_array($key, $optionsSet))
         {
            $this->$method($value);
            $optionsSet[]  = $key;
         }
      }
   }

   public function toArray($givenVars = null, $postProccess = true)
   {
      $vars = get_object_vars($this);
      $methods = get_class_methods($this);
      foreach($vars as $key => $value)
      {
         unset($vars[$key]);
         if($key[0] != '_')
            continue;
         
         if($givenVars !== null && !in_array(substr($key, 1), $givenVars))
            continue;

         // Strip the underscore
         $method = 'get' . ucfirst(substr($key, 1));
         if(in_array($method, $methods))
            $vars[substr($key, 1)] = $this->$method();
      }
      if($postProccess)
         $this->postToArray($vars);
      return $vars;
   }
   
   public function toDom($rootNamespace, $lable)
   {
      $dom = new DOMDocument('1.0', 'utf-8');
      $rootElement = $dom->createElement($rootNamespace);
      $rootElement->setAttribute('xmlns:oslc', "http://open-services.net/ns/core#");
      $rootElement->setAttribute('xmlns:dcterms', "http://purl.org/dc/terms/");
      $rootElement->setAttribute('xmlns:rdf', "http://www.w3.org/1999/02/22-rdf-syntax-ns#");
      $rootElement->setAttribute('xmlns:' . $rootNamespace , "http://www.w3.org/1999/02/22-rdf-syntax-ns#");
      $dom->appendChild($rootElement);
      
      $vars = $this->toArray();
      foreach($vars as $key => $value)
      {
         if($key == 'Description')
            continue;
            
         $element = $dom->createElement($rootNamespace . ':' . $key, $value);
         $rootElement->appendChild($element);
      }
      
      return $dom;
   }

   // Children should implement this function
   // to change the way API calls return data.
   // If you want to change how the database saves information
   // this is NOT the spot to do so.  Look at the Mapper functions.
   protected function postToArray(&$data)
   {
      foreach($this->mExtraFields as $key => $value)
      {
         if(strlen($key) <= 1 || $key[0] !== '_' || $key[1] !== '_')
            continue;

         $data[$key] = $value;
      }
   }

   /**
     * Classes are named spaced using their module name
     * this returns that module name or the first class name segment.
     *
     * @return string This class namespace
     */
    private function _getNamespace()
    {
        $ns = explode('_', get_class($this));
        return $ns[0];
    }

    /**
     * Inflect the name using the inflector filter
     *
     * Changes camelCaseWord to Camel_Case_Word
     *
     * @param string $name The name to inflect
     * @return string The inflected string
     */
    private function _getInflected($name)
    {
        $inflector = new Zend_Filter_Inflector(':class');
        $inflector->setRules(array(
            ':class'  => array('Word_CamelCaseToUnderscore')
        ));
        return ucfirst($inflector->filter(array('class' => $name)));
    }
}

